As software projects grow larger and more complex, techniques for detecting errors in them become more important. A common technique for detecting errors in large commercial systems is through the use of test cases. However, creating good test cases is very difficult, and testing for concurrency errors (errors caused by more than one process or thread being run at the same time) can be extremely frustrating.
There are several different techniques available for diagnosing software. One such technique, model checking, involves algorithmically checking whether a program (the model) satisfies a specification. The model reflects the functional or operational requirements that the program being tested is trying to address. Then test cases, sometimes generated semi-automatically based on scenarios that the program may be involved in, are supplied to the model checker. The model checker then applies the test case to the model and generates the result. Unfortunately model checking tools face a combinational blow up of the state-space, commonly known as the state explosion problem that may require more time or computational power/resources than may be available. For example, when testing a large program (30,000 or more lines) using a model checker the model checker may run out of memory or run out of time before it is able to complete the testing.
Sometimes various metric tools are also used to evaluate the results of the test cases. The test cases may simulate different scenarios but they often are not able to explore all possible situations that a program may encounter. Other attempted solutions include static analysis and run time monitoring but, like a model checker, these techniques are not able to detect every defect in large software systems in an efficient manner. This may be because of one of two reasons, either the technique is not able to reduce the software system being tested to a sufficiently reduce size, or the technique is too aggressive in reducing the size of the software system masking some of the bugs.
Some of the different reduction techniques are environment generation, slicing, and abstraction. In environment generation external constraints to a particular portion of the software are maintained; in slicing the portions of the software that are of interest or related to a particular part of the software are identified; and in abstraction the number of program states associated with the software is reduced.